#include <stdio.h>
#include <stdint.h>
#include <locale.h>
#include <stdlib.h>
#include <windows.h>

// 根据操作系统选择正确的头文件
#ifdef _WIN32
#include <direct.h> // Windows 系统
#else
#include <unistd.h> // Unix/Linux/macOS 系统
#endif


#define NUM (uint8_t)(10)

/* bin文件加密使用的数据 */
#define BYTE_OFFSET (uint8_t)(0xD8)
#define BYTE_XOR (uint8_t)(0xBA)

/* bin文件加密的字节偏移量 */
#define OFFSET_POST (uint8_t)(0)
#define XOR_POST (uint8_t)(8)


/**
 * @brief 从源路径复制并重命名文件到目标路径。
 *
 * 该函数以二进制读取模式打开源文件，并以二进制写入模式打开目标文件。
 * 然后，它会分块读取源文件的内容，并将这些内容写入目标文件中，从而实现文件的复制。
 * 如果在任何步骤（如打开文件、读取或写入）中遇到失败，它会打印错误信息并返回-1。
 * 操作成功完成后，它会打印成功信息并返回0。
 *
 * @param source_path 源文件的路径。
 * @param destination_path 文件应被复制并重命名的目标路径。
 * @return 成功时返回0，失败时返回-1。
 */
int copy_and_rename_file(const char* source_path, const char* destination_path)
{
	FILE* source_file = fopen(source_path, "rb");
	if (!source_file)
	{
		perror("Failed to open source file");
		return -1;
	}

	FILE* destination_file = fopen(destination_path, "wb");
	if (!destination_file)
	{
		perror("Failed to open destination file");
		fclose(source_file);
		return -1;
	}

	unsigned char buffer[4096];
	size_t bytes_read;

	// 读取源文件的内容并写入到目标文件
	while ((bytes_read = fread(buffer, 1, sizeof(buffer), source_file)) > 0)
	{
		if (fwrite(buffer, 1, bytes_read, destination_file) != bytes_read)
		{
			perror("Writing to destination file failed");
			fclose(source_file);
			fclose(destination_file);
			return -1;
		}
	}

	if (ferror(source_file))
	{
		perror("Error reading from source file");
		fclose(source_file);
		fclose(destination_file);
		return -1;
	}

	fclose(source_file);
	fclose(destination_file);

	printf("File copied and renamed successfully.\n");
	return 0;
}


int main(void)
{
	FILE* file = NULL;
	int8_t data[NUM] = {0};
	const char* src_filepath = "../app.bin/app.bin";
	const char* dest_filepath = "../app.bin/app(After encryption).bin";
	char exePath[1024] = {0}; // 缓冲区用于存储可执行文件路径
	char cwd[1024];           // 缓冲区用于存储路径

#ifdef _WIN32
	// 获取可执行文件路径（Windows）
	GetModuleFileName(NULL, exePath, sizeof(exePath));
#else
    // 获取可执行文件路径（Linux/Unix）
    ssize_t len = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
    if (len != -1) {
        exePath[len] = '\0';
    }
#endif

	printf("Executable File Path: %s\n", exePath);

	// 获取当前工作目录
	if (getcwd(cwd, sizeof(cwd)) != NULL)
	{
		printf("Current Working Directory: %s\n", cwd);
	}
	else
	{
		perror("getcwd() error!");
		return -1;
	}

	// 提取可执行文件所在目录
	char* lastSlash = strrchr(exePath, '\\'); // Windows 使用反斜杠
	if (!lastSlash)
	{
		lastSlash = strrchr(exePath, '/'); // Linux/Unix 使用正斜杠
	}

	if (lastSlash)
	{
		*lastSlash = '\0'; // 截断路径，保留目录部分
	}
	printf("lastSlash File Path: %s\n", exePath);

	// 切换工作目录到可执行文件所在目录
	if (chdir(exePath) != 0)
	{
		perror("chdir() error!");
		return -1;
	}

	/* 拷贝加密前bin文件 */
	if (copy_and_rename_file(src_filepath, dest_filepath) != 0)
	{
		printf("Source bin file not found.\n");
		return -1;
	}

	/* 读写方式打开二进制文件 */
	file = fopen(dest_filepath, "rb+");
	if (file == NULL)
	{
		printf("Could not open the file\r\n");
		return -1;
	}

	/* 读取数据 */
	fread(data, 1, sizeof(data), file);

	data[OFFSET_POST] = (int8_t)(data[OFFSET_POST] - BYTE_OFFSET);
	data[XOR_POST] = (int8_t)(data[XOR_POST] ^ BYTE_XOR);

	// 将文件指针移回起始位置
	fseek(file, 0, SEEK_SET);

	// 将修改后的数据写回文件
	fwrite(data, 1, sizeof(data), file);

	fclose(file);

	printf("The upgraded bin file has been successfully created.\r\n");

	return 0;
}